package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"flag"
	"fmt"
	"gitee.com/dongmingchao/decent-ft/src/JSlike"
	"gitee.com/dongmingchao/decent-ft/src/caretaker"
	"gitee.com/dongmingchao/decent-ft/src/cli"
	"gitee.com/dongmingchao/decent-ft/src/courier"
	"gitee.com/dongmingchao/decent-ft/src/event"
	"gitee.com/dongmingchao/decent-ft/src/http"
	"gitee.com/dongmingchao/decent-ft/src/utils"
	"log"
	"math"
	"net"
	"strings"
	"sync"
	"time"
)

var remoteAddr string
var enableHttp bool
var watchDir string

func init() {
	flag.StringVar(&remoteAddr, "h", "", "host")
	flag.StringVar(&watchDir, "w", WatchDir, "the directory will be watched")
	flag.BoolVar(&enableHttp, "web", false, "start a web server")
}

func waitForPresetJobs() {

}

func whenStopCareTaker(args ...JSlike.Any) {
	fmt.Println("[File Watcher] Stop")
	totallyShutdown.Done()
}

func whenStopCourier(args ...JSlike.Any) {
	fmt.Println("[Courier] Stop")
	totallyShutdown.Done()
}

func whenCourierReady(args ...JSlike.Any) {
	fmt.Println("[Courier] Start")
	presetWaiter.Done()
}

func whenCareTakerReady(args ...JSlike.Any) {
	fmt.Println("[File Watcher] Start")
	presetWaiter.Done()
}

var presetWaiter = sync.WaitGroup{}
var totallyShutdown = sync.WaitGroup{}

const (
	WatchDir = "./sample-pool"
)

func start() {
	flag.Parse()
	wg := event.Bus{}
	presetWaiter.Add(2) // 前置工作长度
	totallyShutdown.Add(2)
	wg.On("caretaker-ready", whenCareTakerReady)
	wg.On("courier-ready", whenCourierReady)
	wg.On("stop-caretaker", whenStopCareTaker)
	wg.On("stop-courier", whenStopCourier)
	go caretaker.WatchDir(wg, watchDir)
	go courier.Start(wg)
	if enableHttp {
		fmt.Println("Start A Web Server At localhost:8090")
		go http.Main()
	}
	presetWaiter.Wait()
	cli.Main()
	totallyShutdown.Wait()
}

func main() {
	start()
}

func sliceTest() {
	tt := []string{"a", "b", "c"}
	fmt.Println("head", tt[0])
	fmt.Println("rest", tt[1:])
}

func ipInterfaceTest() {
	ifaces, _ := net.Interfaces()
	ip1, err := net.ResolveTCPAddr("tcp", "192.168.0.155:8090")
	if err != nil {
		log.Fatalln(err)
	}
	// handle err
	for _, i := range ifaces {
		addrs, _ := i.Addrs()
		// handle err
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				fmt.Println("IP Net", v, ip1)
				fmt.Println("contains 192.168.0.155?", v.Contains(ip1.IP))
			case *net.IPAddr:
				ip = v.IP
				fmt.Println("IP Addr", ip.String())
			}
			// process IP address
		}
	}
}

func writeStringTest() {
	var out bytes.Buffer
	out.WriteString("abc")
	out.WriteByte(0)
	reader := bufio.NewReader(&out)
	s, _ := reader.ReadString(0)
	s = strings.TrimRight(s, string(0))
	fmt.Println("s byte", []byte(s))
}

func sameStringTest() {
	a := "sample-pool/lan.txt"
	b := "sample-pool/lan.txt"
	fmt.Println("same?", a == b)
}

func stringArrayWriteTest() {
	var ss []string
	ss = append(ss, "aaa", "bbb", "ccc")
	var out bytes.Buffer
	binary.Write(&out, binary.BigEndian, ss)
	fmt.Println("res", out.String()) // 啥都没有
}

func intMaxLength() {
	const MaxUint = ^uint(0)
	const MinUint = 0
	const MaxInt = int(MaxUint >> 1)
	const MinInt = -MaxInt - 1
	fmt.Println(MaxInt)
	fmt.Println(math.MaxInt64)
}

func testIPBinary() {
	var sent bytes.Buffer
	srcAddr, _ := net.ResolveUDPAddr("udp", "192.168.1.1:51664")
	addr := utils.NewUDPAddr(srcAddr)
	addr.Write(&sent)
	fmt.Println(sent.Bytes(), sent.Len())
	rr := utils.UDPAddr{}
	rr.Read(&sent)
	fmt.Println("read: ", rr)
}

func readerRestTest() {
	var buf bytes.Buffer
	buf.WriteString("abc")
	tt := bytes.NewReader(buf.Bytes())
	tt.ReadByte()
	fmt.Println("rest len", tt.Len())
	var beWrote bytes.Buffer
	tt.WriteTo(&beWrote)
	fmt.Println("rest", beWrote.String())
}

func readerStringTest() {
	var buf bytes.Buffer
	buf.WriteString("abc")
	buf.WriteByte(0)
	buf.WriteByte(3)
	res := bufio.NewReader(bytes.NewReader(buf.Bytes()))
	str, _ := res.ReadString(0)
	code, _ := res.ReadByte()
	fmt.Println("read", str, code)
}

func channelRecvText() {
	tc := make(chan int)
	closed := false
	i := 0
	go func() {
		for i < 7 {
			//time.Sleep(time.Second)
			i++
			fmt.Println("i =", i)
			if closed {
				return
			}
			tc <- i
			fmt.Println("other works")
		}
	}()
	fmt.Println("got", <-tc)
	time.Sleep(5 * time.Second)
	fmt.Println("got after 5s", <-tc, i)
	println("remain", len(tc))
	close(tc)
	closed = true
	time.Sleep(5 * time.Second)
}

func closeChannelTest() {
	ww := make(chan int)
	wg := sync.WaitGroup{}
	wg.Add(1)
	go func() {
		<-ww
		wg.Done()
		fmt.Println("exec after ww")
	}()
	go func() {
		fmt.Println("after 1s I want stop recv")
		time.Sleep(time.Second)
		close(ww)
	}()
	fmt.Println("wait for ww")
	wg.Wait()
}
